/**
 * Copyright (c) 2018 开源 All rights reserved.
 * <p>
 * https://www.chengcang.com
 * <p>
 * 版权所有，侵权必究！
 */

package com.chengcang.admin.modules.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.chengcang.common.enums.DataTypeEnum;
import com.chengcang.admin.modules.log.dto.SysLogLoginDTO;
import com.chengcang.admin.modules.log.service.SysLogLoginService;
import com.chengcang.admin.modules.security.service.SysUserTokenService;
import com.chengcang.admin.modules.sys.dao.*;
import com.chengcang.admin.modules.sys.dto.SysUserUpdateDTO;
import com.chengcang.admin.modules.sys.entity.*;
import com.chengcang.admin.modules.sys.service.*;
import com.chengcang.common.utils.PasswordUtils;
import com.chengcang.admin.modules.security.user.SecurityUser;
import com.chengcang.admin.modules.security.user.UserDetail;
import com.chengcang.admin.modules.sys.dto.SysUserDTO;
import com.chengcang.common.enums.SuperAdminEnum;
import com.chengcang.common.constant.Constant;
import com.chengcang.common.exception.CustomException;
import com.chengcang.common.page.PageData;
import com.chengcang.common.service.impl.BaseServiceImpl;
import com.chengcang.common.utils.ConvertUtils;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;


/**
 * 系统用户
 *
 * @author zhanli
 */
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl extends BaseServiceImpl<SysUserDao, SysUserEntity> implements SysUserService {

    private final SysRoleUserService sysRoleUserService;
    private final SysDeptDao sysDeptDao;
    private final SysRoleDao sysRoleDao;
    private final SysDeptService sysDeptService;
    private final SysDictDataService sysDictDataService;
    private final SysUserTenantDao sysUserTenantDao;
    private final SysLogLoginService sysLogLoginService;
    private final SysUserTokenService sysUserTokenService;

    @Override
    public PageData<SysUserDTO> page(Map<String, Object> params) {

        params.put("tenantId1", SecurityUser.getTenantId());
        //转换成like
        paramsToLike(params, "username");

        //分页
        IPage<SysUserEntity> page = getPage(params, Constant.CREATE_DATE, false);

        //普通管理员，只能查询所属部门及子部门的数据
        UserDetail user = SecurityUser.getUser();
        if (SecurityUser.getUserType() == SuperAdminEnum.NO.value()) {
            params.put("deptIdList", sysDeptService.getSubDeptIdList(user.getDeptId()));
        }

        //查询
        List<SysUserEntity> list = baseDao.getList(params);

        PageData<SysUserDTO> pageData = getPageData(list, page.getTotal(), SysUserDTO.class);
        for (SysUserDTO userDTO : pageData.getList()) {

            Long userId = userDTO.getId();
            //查询最后登陆时间
            SysLogLoginDTO sysLogLoginDTO = sysLogLoginService.selectLastLoginTime(userId);
            Optional.ofNullable(sysLogLoginDTO).ifPresent(o -> userDTO.setLastLoginTime(o.getCreateDate()));

            userDTO.setUserTypeName(sysDictDataService.getValue(DataTypeEnum.USER_TYPE, String.valueOf(userDTO.getDefaultUserType())));
            userDTO.setSourceName(sysDictDataService.getValue(DataTypeEnum.DATA_SOURCE, String.valueOf(userDTO.getSource())));
            userDTO.setStatusName(sysDictDataService.getValue(DataTypeEnum.USER_STATUS, String.valueOf(userDTO.getStatus())));
            Optional.ofNullable(userDTO.getDeptId()).ifPresent(o -> {
                SysDeptEntity sysDeptEntity = sysDeptDao.selectById(o);
                Optional.ofNullable(sysDeptEntity).ifPresent(o1 -> {
                    if (StringUtils.isNotBlank(o1.getPids()) && !Objects.equals("0", sysDeptEntity.getPids())) {
                        userDTO.setDeptIds(o1.getPids() + "," + o1.getId());
                    } else {
                        userDTO.setDeptIds(String.valueOf(o1.getId()));
                    }
                });
            });
        }
        return pageData;
    }

    @Override
    public List<SysUserDTO> list(Map<String, Object> params) {
        //普通管理员，只能查询所属部门及子部门的数据
        UserDetail user = SecurityUser.getUser();
        if (SecurityUser.getUserType() == SuperAdminEnum.NO.value()) {
            params.put("deptIdList", sysDeptService.getSubDeptIdList(user.getDeptId()));
        }
        params.put("status", 0);
        params.put("tenantId", SecurityUser.getTenantId());
        List<SysUserEntity> entityList = baseDao.getList(params);

        return ConvertUtils.sourceToTarget(entityList, SysUserDTO.class);
    }

    @Override
    public SysUserDTO get(Long id) {
        SysUserEntity entity = baseDao.getById(id);

        SysUserDTO userDTO = ConvertUtils.sourceToTarget(entity, SysUserDTO.class);
        List<UserTenant> userTenantEntities = sysUserTenantDao.selectUserTenant(id);
        if (userTenantEntities.size() == 0) {
            throw new CustomException("未查询到相关用户！");
        }
        userDTO.setUserTypeName(sysDictDataService.getValue(DataTypeEnum.USER_TYPE, String.valueOf(userDTO.getDefaultUserType())));
        userDTO.setSourceName(sysDictDataService.getValue(DataTypeEnum.DATA_SOURCE, String.valueOf(userDTO.getSource())));
        userDTO.setStatusName(sysDictDataService.getValue(DataTypeEnum.USER_STATUS, String.valueOf(userDTO.getStatus())));
        if (CollectionUtils.isNotEmpty(userTenantEntities)) {
            for (UserTenant tenantEntity : userTenantEntities) {
                tenantEntity.setUserTypeName(sysDictDataService.getValue(DataTypeEnum.USER_TYPE, String.valueOf(tenantEntity.getUserType())));
            }
            userDTO.setTenantList(userTenantEntities);
        }
        //用户角色列表
        List<Long> roleIdList = sysRoleUserService.getRoleIdList(id);
        if (!CollectionUtils.isEmpty(roleIdList)) {
            userDTO.setRoleId(roleIdList.get(0));
            SysRoleEntity sysRoleEntity = sysRoleDao.selectById(roleIdList.get(0));
            Optional.ofNullable(sysRoleEntity).ifPresent(o -> userDTO.setRoleName(sysRoleEntity.getName()));
        }
        return userDTO;
    }

    @Override
    public SysUserDTO getByUsername(String username) {
        SysUserEntity entity = baseDao.getByUsername(username);
        return ConvertUtils.sourceToTarget(entity, SysUserDTO.class);
    }

    private void check(SysUserDTO dto) {
        String mobile = dto.getMobile();
        Long userId = dto.getId();
        if (baseDao.exists(new LambdaQueryWrapper<SysUserEntity>().eq(SysUserEntity::getMobile, mobile).ne(userId != null, SysUserEntity::getId, userId))) {
            throw new CustomException("手机号已存在，不允许重复创建！");
        }

        // 校验部门和角色是否已经禁用
        Long deptId = dto.getDeptId();
        Optional.ofNullable(deptId).ifPresent(o -> {
            SysDeptEntity sysDeptEntity = sysDeptDao.selectById(deptId);
            Optional.ofNullable(sysDeptEntity).orElseThrow(() -> new CustomException("部门不存在！"));
            if (sysDeptEntity.getStatus() != 0) {
                throw new CustomException("部门已被禁用！");
            }
        });
        Long roleId = dto.getRoleId();
        Optional.ofNullable(roleId).ifPresent(o -> {
            {
                SysRoleEntity sysRoleEntity = sysRoleDao.selectById(roleId);
                if (sysRoleEntity == null) {
                    throw new CustomException("职务不存在！");
                }
                if (sysRoleEntity.getStatus() != 0) {
                    throw new CustomException("职务已被禁用！");
                }
            }
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(SysUserDTO dto) {
        SysUserEntity entity = ConvertUtils.sourceToTarget(dto, SysUserEntity.class);

        check(dto);
        // 手机号作为用户名
        entity.setUsername(dto.getMobile());

        //密码加密
        String password = PasswordUtils.encode(dto.getPassword());
        entity.setPassword(password);

        //保存用户
        entity.setDefaultUserType(SuperAdminEnum.NO.value());
        entity.setDefaultTenantId(SecurityUser.getTenantId());
        entity.setStatus(0);
        insert(entity);

        SysUserTenantEntity sysUserTenant = new SysUserTenantEntity();
        sysUserTenant.setUserType(SuperAdminEnum.NO.value());
        sysUserTenant.setUserId(entity.getId());
        sysUserTenant.setTenantId(SecurityUser.getTenantId());

        sysUserTenantDao.insert(sysUserTenant);

        //保存角色用户关系
        if (dto.getRoleId() != null) {
            sysRoleUserService.saveOrUpdate(entity.getId(), Arrays.asList(dto.getRoleId()));
        } else {
            sysRoleUserService.saveOrUpdate(entity.getId(), null);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(SysUserDTO dto) {
        SysUserEntity entity = ConvertUtils.sourceToTarget(dto, SysUserEntity.class);

        check(dto);
        // 管理员账号不允许修改username,手机号作为用户名
        SysUserDTO sysUserDTO = get(dto.getId());
        if (sysUserDTO != null && sysUserDTO.getUsername() != null && !"admin".equals(sysUserDTO.getUsername())) {
            entity.setUsername(dto.getMobile());
        }
        //密码加密
        if (StringUtils.isBlank(dto.getPassword())) {
            entity.setPassword(null);
        } else {
            String password = PasswordUtils.encode(entity.getPassword());
            entity.setPassword(password);
        }

        if (dto.getDeptId() == null) {
            dto.setDeptId(null);
        }
        //更新用户
//        updateById(entity);
        UpdateWrapper<SysUserEntity> updateWrapper = new UpdateWrapper<>();
        if (dto.getDeptId() == null) {
            updateWrapper.set("dept_id", null);
        }
        updateWrapper.eq("id", dto.getId());
        baseDao.update(entity, updateWrapper);

        if (dto.getRoleId() != null) {
            sysRoleUserService.saveOrUpdate(entity.getId(), Arrays.asList(dto.getRoleId()));
        } else {
            sysRoleUserService.saveOrUpdate(entity.getId(), null);
        }

        // 更新缓存
        sysUserTokenService.clearCache(dto.getId());
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateBatch(SysUserUpdateDTO dto) {
        // 修改部门
        Optional.ofNullable(dto.getDeptId()).ifPresent(id -> {
            SysUserEntity sysUserEntity = new SysUserEntity();
            sysUserEntity.setDeptId(id);
            sysUserEntity.setRemark(dto.getRemark());
            baseDao.update(sysUserEntity, new LambdaQueryWrapper<SysUserEntity>().in(SysUserEntity::getId, dto.getIds()));
        });

        //更新角色用户关系
        Optional.ofNullable(dto.getRoleId()).ifPresent(o -> {
            List<SysUserEntity> sysUserEntities = baseDao.selectList(new LambdaQueryWrapper<SysUserEntity>().in(SysUserEntity::getId, dto.getIds()));
            sysUserEntities.forEach(o1 -> o1.setRemark(dto.getRemark()));
            for (SysUserEntity sysUserEntity : sysUserEntities) {
                baseDao.updateById(sysUserEntity);
            }
            for (Long id : dto.getIds()) {
                sysRoleUserService.saveOrUpdate(id, Collections.singletonList(o));
            }
        });
        // 清理用户缓存
        sysUserTokenService.clearCache(dto.getIds());
    }

    @Override
    public void delete(Long[] ids) {
        //删除用户
        baseDao.deleteBatchIds(Arrays.asList(ids));

        //删除角色用户关系
        sysRoleUserService.deleteByUserIds(ids);

        // 清理用户缓存
        sysUserTokenService.clearCache(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePassword(Long id, String newPassword) {
        newPassword = PasswordUtils.encode(newPassword);

        baseDao.updatePassword(id, newPassword);
        // 直接登出
        sysUserTokenService.logout(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetPassword(List<Long> ids, String remark) {
        String newPassword = PasswordUtils.encode(PasswordUtils.DEFAULT_PASSWORD);

        baseDao.resetPassword(ids, newPassword, remark, SecurityUser.getTenantId());

        // 直接登出
        for (Long id : ids) {
            sysUserTokenService.logout(id);
        }
    }

    @Override
    public int getCountByDeptId(Long deptId) {
        return baseDao.getCountByDeptId(deptId);
    }

    @Override
    public List<Long> getUserIdListByDeptId(List<Long> deptIdList) {
        return baseDao.getUserIdListByDeptId(deptIdList);
    }

    @Override
    public void forbidTenant(Long[] ids, Integer status, String remark) {
        for (Long id : ids) {
            SysUserEntity userEntity = baseDao.getById(id);
            if (userEntity.getDefaultTenantId() != null) {
                SysUserEntity sysUserEntity = new SysUserEntity();
                sysUserEntity.setStatus(status);
                sysUserEntity.setId(id);
                sysUserEntity.setRemark(remark);
                baseDao.updateById(sysUserEntity);
                if (status == 1) {
                    sysUserTokenService.logout(id);
                }
            }
        }
    }

    @Override
    public PageData<SysUserDTO> rolePage(Map<String, Object> params) {

        Object roleId = params.get("roleId");
        Optional.ofNullable(roleId).orElseThrow(() -> new CustomException("角色ID不能为空！"));
        Optional.ofNullable(SecurityUser.getTenantId()).ifPresent(o -> params.put("tenantId", SecurityUser.getTenantId()));
        // 查询用户
        IPage<SysUserEntity> page = getPage(params, Constant.CREATE_DATE, false);
        List<SysUserEntity> list = baseDao.selectListByRoleId(params);
        PageData<SysUserDTO> pageData = getPageData(list, page.getTotal(), SysUserDTO.class);

        Map<Long, String> deptNameMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(list)) {
            List<String> deptIds = list.stream().filter(o -> StringUtils.isNotBlank(o.getDeptIds()))
                    .flatMap(o -> Arrays.stream(StringUtils.split(o.getDeptIds() + "," + o.getDeptId(), ",")))
                    .distinct().collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(deptIds)) {
                List<SysDeptEntity> sysDeptEntities = sysDeptDao.selectBatchIds(deptIds);
                if (CollectionUtils.isNotEmpty(sysDeptEntities)) {
                    deptNameMap = sysDeptEntities.stream().collect(Collectors.toMap(SysDeptEntity::getId, SysDeptEntity::getName));
                }
            }
        }
        for (SysUserDTO userDTO : pageData.getList()) {
            userDTO.setRoleId(Long.parseLong(String.valueOf(roleId)));

            Map<Long, String> finalDeptNameMap = deptNameMap;
            Optional.ofNullable(userDTO.getDeptIds()).ifPresent(o -> {
                ArrayList<String> deptNameAppend = new ArrayList<>();
                for (String deptId : StringUtils.split(o, ",")) {
                    Optional.ofNullable(finalDeptNameMap.get(Long.valueOf(deptId))).ifPresent(deptNameAppend::add);
                }
                deptNameAppend.add(finalDeptNameMap.get(userDTO.getDeptId()));
                Collections.reverse(deptNameAppend);
                userDTO.setDeptName(StringUtils.join(deptNameAppend, "/"));
            });
        }
        return pageData;
    }

}
